package com.lunhui.service.provider.controller;

import com.alibaba.fastjson.JSONObject;
import com.lunhui.cache.client.model.LoginUserDto;
import com.lunhui.service.lunhui.service.business.CacheService;
import com.lunhui.service.lunhui.service.business.UserService;
import com.lunhui.service.lunhui.service.business.enums.DatasourceEnum;
import com.lunhui.service.lunhui.service.business.enums.ResultCodeEnum;
import com.lunhui.service.provider.common.Result;
import com.lunhui.service.provider.common.threads.UpdateUserInfoThread;
import com.lunhui.user.client.model.RoseDto;
import com.lunhui.user.client.model.UserDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author renminghe-kg
 */

@RestController
@Api(value = "用户接口")
@RequestMapping("user")
public class LunHuiServiceUserController {
    private static final Logger logger = LoggerFactory.getLogger(LunHuiServiceUserController.class);

    @Autowired
    @Qualifier("userService")
    private UserService userService;

    @Autowired
    @Qualifier("cacheService")
    private CacheService cacheService;

    @ApiOperation(value = "注册", httpMethod = "POST")
    @RequestMapping(value = "register", method = RequestMethod.POST)
    @ResponseBody
    public Result<String> register(@ApiParam("账号") @RequestParam(name = "account") String account,
                                   @ApiParam("密码") @RequestParam(name = "password") String password) {

        if (account == null || password == null) {
            return Result.fail("账号或密码不能为空");
        }

        try {

            UserDto byAccount = userService.findByAccount(account);
            if (byAccount != null && byAccount.getAccount() != null) {
                return Result.fail("账号已存在");
            }

            Integer integer = userService.saveToDB(account, password);
            if (integer != 1) {
                return Result.fail("注册失败");
            }

            return Result.ok();

        } catch (Exception e) {
            logger.error("注册失败: " + e.getMessage());
            return Result.fail("注册失败");
        }

    }

    @ApiOperation(value = "登录", httpMethod = "POST")
    @RequestMapping(value = "login", method = RequestMethod.POST)
    @ResponseBody
    public Result login(@ApiParam("账号") @RequestParam(name = "account") String account,
                        @ApiParam("密码") @RequestParam(name = "password") String password) {

        if (account == null || password == null) {
            return Result.fail("账号或密码不能为空");
        }

        try {

            UserDto userDto = userService.findByAccountAndPassword(account, password);
            if (userDto == null) {
                return Result.fail("账号或密码错误");
            }

            // 更新登录时间
            userDto.setLastLoginTime(nowDate());

            ExecutorService fixedPool = Executors.newFixedThreadPool(2);
            CompletionService<Map<DatasourceEnum, Object>> completionService = new ExecutorCompletionService<>(fixedPool);
            try {

                LoginUserDto loginUserDto = new LoginUserDto();
                BeanUtils.copyProperties(userDto, loginUserDto);

                UpdateUserInfoThread userInfoThread = new UpdateUserInfoThread(cacheService, loginUserDto);
                UpdateUserInfoThread userInfoThread1 = new UpdateUserInfoThread(userService, userDto);

                completionService.submit(userInfoThread);
                completionService.submit(userInfoThread1);
            } catch (Exception e) {
                logger.error("更新用户数据失败: " + e.getMessage());
            } finally {
                fixedPool.shutdown();
            }

            Map<DatasourceEnum, Object> resultMap;
            for (int i = 0; i < 2; i ++) {
                try {
                    Future<Map<DatasourceEnum, Object>> futureTask = completionService.take();
                    resultMap = futureTask.get();
                } catch (Exception e) {
                    logger.error(
                            "从 CompletionService<Map<DatasourceEnum, Object>>" +
                                    "或Future<Map<DatasourceEnum, Object>>中获取结果失败: " + e.getMessage());

                    continue;
                }

                if (resultMap == null) {
                    continue;
                }

                if (resultMap.containsKey(DatasourceEnum.USER_CACHE_REDIS)) {
                    logger.info("更新用户缓存成功");
                    continue;
                }
                if (resultMap.containsKey(DatasourceEnum.USER_INFO_MYSQL)) {
                    logger.info("更新用户数据库成功");
                }
            }



            // token
            String userId = userDto.getUserId().toString();
            String token = encodeToken(userId, userDto.getCreateTime(), userDto.getLastLoginTime());

            HashMap<String, String> resMap = new HashMap<>();
            resMap.put("userId", userId);
            resMap.put("token", token);

            return Result.ok(JSONObject.toJSONString(resMap));

        } catch (Exception e) {
            logger.error("登录失败: " + e.getMessage());
            return Result.fail("登录失败");
        }
    }

    @ApiOperation(value = "通过userId获取角色列表", httpMethod = "GET")
    @RequestMapping(value = "roseNameListInfo", method = RequestMethod.GET)
    @ResponseBody
    public Result<List<RoseDto>> getRoseNameListByUserId(Integer userId, String token) {
        if (userId == null || token == null) {
            return Result.fail("用户Id或token不能为空");
        }

        try {

            List<RoseDto> roseNameList = userService.findRoseNameListByUserId(userId);
            logger.info("通过userId获取角色列表数据: " + JSONObject.toJSONString(roseNameList));
            return Result.ok(roseNameList);
        } catch (Exception e) {
            logger.error("获取角色列表失败: " + e.getMessage());
            return Result.fail("获取角色失败");
        }
    }

    @ApiOperation(value = "创建角色", httpMethod = "POST")
    @RequestMapping(value = "createRose", method = RequestMethod.POST)
    @ResponseBody
    public Result createRose(@ApiParam("用户id") @RequestParam(name = "userId") Integer userId,
                             @ApiParam("token") @RequestParam(name = "token") String token,
                             @ApiParam("角色名") @RequestParam(name = "roseName") String roseName) {
       if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(token) || StringUtils.isEmpty(roseName)) {
           return Result.fail("参数不能为空");
       }

        Integer resultFlag;
        RoseDto roseDto = new RoseDto();

        try {
            roseDto.setRoseUserId(userId);
            roseDto.setRoseSex(Boolean.valueOf("0"));
            roseDto.setRoseName(roseName);

            resultFlag = userService.crateRose(roseDto);
        } catch (Exception e) {
            logger.error("创建角色失败: " + e);
            return Result.fail(ResultCodeEnum.EXCEPTION_CODE.getCode(),
                    ResultCodeEnum.EXCEPTION_CODE.getName());
        }

        if (!resultFlag.equals(1)) {
            return Result.fail(ResultCodeEnum.EXCEPTION_CODE.getCode(),
                    ResultCodeEnum.EXCEPTION_CODE.getName());
        }

        return Result.ok();
    }

    // encode
    private String encodeToken(String... strings) {
        StringBuilder sourceStr = new StringBuilder();

        for (String i : strings) {
            sourceStr.append(i);
        }

        return DigestUtils.md5Hex(sourceStr.toString());
    }


    private String nowDate() {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return LocalDateTime.now().format(df);
    }

}